package com.group9.handinhand.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.group9.handinhand.dao.UserDao;
import com.group9.handinhand.dao.model.Friendship;
import com.group9.handinhand.dao.model.FriendshipRequest;
import com.group9.handinhand.dao.model.PasswordResetLink;
import com.group9.handinhand.dao.model.User;
import com.group9.handinhand.exception.HandInHandException;
import com.group9.handinhand.service.so.FriendshipRequestSO;
import com.group9.handinhand.service.so.FriendshipSO;
import com.group9.handinhand.service.so.PasswordResetLinkSO;
import com.group9.handinhand.service.so.UserEnums.UserStatus;
import com.group9.handinhand.service.so.UserSO;

@Transactional
@Service("userService")
public class UserServiceImpl implements UserService{
	
	@Autowired
	private UserDao userDao;
	
	@Override
	public List<User> getAllUsers() {
		return userDao.findAllUsers();
	}
	/**
	 * Changes the user status as registered
	 * @param userSo
	 */
	@Override
	public UserSO registerUser(UserSO userSo) {
		userSo.setStatus(UserStatus.ACTIVE);
		User model = userDao.saveUser(userSo.convertToModelObject());
		if(model != null)
			return model.convertToServiceObject();
		return null;
	}
	/**
	 * Updates user.
	 * @param userSo
	 */
	@Override
	public UserSO updateUser(UserSO userSo) {
		User user = userDao.updateUser(userSo.convertToModelObject());
		if(user != null)
			return user.convertToServiceObject();
		return null;
	}
	/**
	 * Gets the user with id.
	 * @param userId
	 * @return user service object
	 * 
	 */
	@Override
	public UserSO getUserById(Long userId) {
		User model = userDao.findUserById(userId);
		if(model != null) {
			return model.convertToServiceObject();
		}
		return null;
	};
	/**
	 * Gets the user with e-mail.
	 * @param email
	 * @return user service object
	 */
	@Override
	public UserSO getUserByEmail(String email) {
		User user = userDao.findUserByEmail(email);
		if(user != null)
			return user.convertToServiceObject();
		return null;
	}
	/**
	 * Gets the user with user name
	 * @param username
	 * @return user service object
	 */
	@Override
	public UserSO getUserByUsername(String username) {
		User user = userDao.findUserByUsername(username);
		if(user != null)
			return user.convertToServiceObject();
		return null;
	}
	/**
	 * Gets the user with e-mail and password.
	 * @param email
	 * @param password
	 * @return user service object
	 */
	@Override
	public  User getUserByEmailAndPassword(String email, String password) throws HandInHandException {
		User user = userDao.findUserByEmail(email);
		if (user == null) {
			return null;
		} else if (!user.getPassword().equals(password)) {
			throw new HandInHandException("Wrong password!");
		} else {
			return user;
		}
	}
	@Override
	public User getUserByUsernameAndPassword(String username, String password) throws HandInHandException {
		User user = userDao.findUserByUsername(username);
		if (user == null) {
			return null;
		} else if (!user.getPassword().equals(password)) {
			throw new HandInHandException("Wrong password!");
		} else {
			return user;
		}
	}
	
	@Override
	public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException {
		UserSO user = getUserByUsername(usernameOrEmail);
        if (user == null) {
        	user = getUserByEmail(usernameOrEmail);
        	if(user == null)
        		throw new UsernameNotFoundException("user not found");
        } 
             
        return user;
	}

	@Override
	public FriendshipSO getFriendship(Long firstUserId, Long secondUserId) {
		Friendship model = userDao.findFriendship(firstUserId, secondUserId);
		if(model == null) {
			model = userDao.findFriendship(secondUserId, firstUserId);
		}
		if(model != null) {
			return model.convertToServiceObject();
		}
		return null;
	}
	/**
	 * Saves the friendship request with sender id and receiver id.
	 * @param senderId
	 * @param receiverId
	 */
	@Override
	public FriendshipRequestSO saveFriendshipRequest(Long senderId, Long receiverId) {
		FriendshipRequest model = null;
		User sender = userDao.findUserById(senderId);
		User receiver = userDao.findUserById(receiverId);
		if(sender != null && receiver != null) {
			model = new FriendshipRequest();
			model.setSender(sender);
			model.setReceiver(receiver);
			model = userDao.saveFriendshipRequest(model);
		}
		if(model != null) {
			return model.convertToServiceObject();
		}
		return null;
	}
	/**
	 * Gets the friendship requests with user id
	 * @param userId
	 * @return the list of friendship requests
	 */
	@Override
	public ArrayList<FriendshipRequestSO> getFriendshipRequests(Long userId) {
		List<FriendshipRequest> modelList = userDao.findAllFriendshipRequestsByUserId(userId);
		ArrayList<FriendshipRequestSO> soList = new ArrayList<FriendshipRequestSO>();
		if(modelList != null) {
			for(FriendshipRequest model : modelList){
				soList.add(model.convertToServiceObject());
			}
			return soList;
		}
		return null;
	}

	@Override
	public ArrayList<FriendshipSO> getFriendships(Long userId) {
		List<Friendship> modelList = userDao.findAllFriendshipsByUserId(userId);
		ArrayList<FriendshipSO> soList = new ArrayList<FriendshipSO>();
		if(modelList != null) {
			for(Friendship model:modelList){
				soList.add(model.convertToServiceObject());
			}
			return soList;
		}
		return null;
	}
	

	@Override
	public FriendshipRequestSO getFriendshipRequest(Long userId1, Long userId2) {
		FriendshipRequest model = userDao.findFriendshipRequestBySenderIdAndReceiverId(userId1, userId2);
		
		if(model == null) {
			model = userDao.findFriendshipRequestBySenderIdAndReceiverId(userId2, userId1);
		}
		if(model != null) {
			return model.convertToServiceObject();
		}
		
		return null;
	}
	
	@Override
	public FriendshipSO saveFriendship(Long firstUserId, Long secondUserId) {
		User firstUser = userDao.findUserById(firstUserId);
		User secondUser = userDao.findUserById(secondUserId);
		if( firstUser != null && secondUser != null) {
			Friendship model = new Friendship();
			model.setFirstUser(firstUser);
			model.setSecondUser(secondUser);
			model = userDao.saveFriendship(model);
			if(model != null)
				return model.convertToServiceObject();
		}
		return null;
	}
	/**
	 * Deletes the friendship request with sender id and receiver id
	 * @param senderId
	 * @param receiverId
	 * 
	 */
	@Override
	public void deleteFriendshipRequest(Long senderId, Long receiverId) {
		FriendshipRequest model = userDao.findFriendshipRequestBySenderIdAndReceiverId(senderId, receiverId);
		userDao.deleteFriendshipRequest(model);
	}

	@Override
	public void deleteFriendship(Long firstUserId, Long secondUserId) {
		Friendship model = userDao.findFriendship(firstUserId, secondUserId);
		if(model == null) {
			model = userDao.findFriendship(secondUserId, firstUserId);
		}
		if(model != null) {
			userDao.deleteFriendship(model);
		}
	}

	@Override
	public PasswordResetLinkSO savePasswordResetLink(UserSO user, String nextRandomPasswordResetLink) {
		User userModel = userDao.findUserById(user.getId());
		if(userModel != null) {
			PasswordResetLink link = new PasswordResetLink();
			link.setLink(nextRandomPasswordResetLink);
			link.setUser(userModel);
			link = userDao.savePasswordResetLink(link);
			if(link != null) 
				return link.convertToServiceObject();
		}
		return null;
	}

	@Override
	public PasswordResetLinkSO getPasswordResetLinkByLink(String link) {
		PasswordResetLink model = userDao.findPasswordResetLinkByLink(link);
		if(model != null)
			return model.convertToServiceObject();
		return null;
	}

	@Override
	public void deletePasswordResetLinksOfUser(UserSO user) {
		List<PasswordResetLink> links = userDao.findPasswordResetLinksByUserId(user.getId());
		for (PasswordResetLink passwordResetLink : links) {
			userDao.deletePasswordResetLink(passwordResetLink);
		}
	}
	@Override
	public UserSO deletePicture(UserSO userSo) {
		User user = userDao.deletePicture(userSo.convertToModelObject());
		if(user != null)
			return user.convertToServiceObject();
		return null;
	}

}
